﻿using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using Casamiel.API.Application.Commands;
using Casamiel.API.Application.Models;
using Casamiel.API.Application.Services;
using Casamiel.API.Infrastructure;
using Casamiel.API.Infrastructure.Filters;
using Casamiel.API.Infrastructure.Middlewares;
using Casamiel.Application;
using Casamiel.Common;
using Casamiel.Common.Extensions;
using Casamiel.Domain;
using Casamiel.Domain.Entity;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
using NLog;
using MediatR;
using Casamiel.API.Controllers;
using Casamiel.Domain.Response;
using System.Globalization;
using Casamiel.API.Application;
using Microsoft.Extensions.Options;
using Casamiel.Domain.Request;

namespace Casamiel.API.Controllers.V2
{
    /// <summary>
    /// 
    /// </summary>
    [Produces("application/json")]
    [ApiVersion("2.0")]
    [Route("api/v{version:apiVersion}/Login")]//{version:apiVersion}
    [Authorize]
    [ApiController]
    //[ApiVersionNeutral]
    public class LoginController : BaseController
    {
        private IMobileCheckCode _mobileCheckCode;
        private IIcApiService _iicApiService;
        private IMemberService _memberService;
        private IMemberCardService _memberCard;
        private readonly IStoreApiService _storeApiService;
        //private readonly ICasamielIntegrationEventService _casamielIntegrationEventService;
        //private readonly CasamielContext _context;
        //private readonly ICacheService _cacheService;
        private readonly IUserLogService _userLog;
        private readonly NLog.ILogger logger = LogManager.GetLogger("BizInfo");
        private readonly ITokenProvider _tokenProvider;
        private readonly IMediator _mediator;
        private readonly CasamielSettings _casamielSettings;
        /// <summary>
        /// 
        /// </summary>
        /// <param name="iicApiService"></param>
        /// <param name="mobileCheckCode"></param>
        /// <param name="memberService"></param>
        /// <param name="memberCard"></param>
        /// <param name="tokenProvider"></param>
        /// <param name="userLog"></param>
        /// <param name="mediator"></param>
        /// <param name="storeApiService"></param>
        /// <param name="snapshot"></param>
        public LoginController(
            IIcApiService iicApiService,
            IMobileCheckCode mobileCheckCode,
            IMemberService memberService,
            IMemberCardService memberCard,
            
            ITokenProvider tokenProvider,
        IUserLogService userLog,
        IMediator mediator, IStoreApiService storeApiService, IOptionsSnapshot<CasamielSettings> snapshot)
        {
            if (snapshot is null) {
                throw new ArgumentNullException(nameof(snapshot));
            }

            _iicApiService = iicApiService;
            _mobileCheckCode = mobileCheckCode;
            _memberCard = memberCard;
            _memberService = memberService;
            _userLog = userLog;
            //_cacheService = cacheService;
            _tokenProvider = tokenProvider;
            _mediator = mediator;
            _storeApiService = storeApiService;
            _casamielSettings = snapshot.Value;
        }
        /// <summary>
        ///获取登陆手机验证码
        /// </summary>
        /// <param name="data">手机号{"mobile":""}</param>
        /// <returns></returns>
        [HttpPost]
        [Route("[action]")]
        public async Task<IActionResult> GetLoginCheckCode([FromBody] GetSmsCodeRequest data)
        {
            if (data == null) {
                throw new ArgumentNullException(nameof(data));
            }

            //if (string.IsNullOrEmpty(data["mobile"].ToString())) {
            //    return new JsonResult(new { code = -5, msg = "手机号不能为空" });
            //}
            string mobile = data.Mobile;
            if (string.IsNullOrEmpty(mobile)) {
                return new JsonResult(new { code = -5, msg = "手机号不能为空" });
            }
            var member = await _memberService.FindAsync<ICasaMielSession>(mobile).ConfigureAwait(false);
            if (member == null) {
                return new JsonResult(new { code = -19, msg = "请先注册" });
            }
            var msg = await _mobileCheckCode.SendCheckCodeAsync(mobile).ConfigureAwait(false);
            if (string.IsNullOrEmpty(msg)) {
                return new JsonResult(new { code = 0, msg = "验证码已发送" });
            }
            return new JsonResult(new { code = -6, msg = "验证码发送失败" });
        }
        /// <summary>
        /// 新接口，会员token刷新
        /// </summary>
        /// <param name="data"></param>
        /// <param name="token"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("[action]")]

        [TypeFilterAttribute(typeof(CheckTokenAttribute))]
        public async Task<IActionResult> RefreshUserToken(
        [FromBody] UserTokenDto data, [FromHeader(Name = "u-token")] string token)
        {
            if (data == null) {
                throw new ArgumentNullException(nameof(data));
            }

            Common.ConsoleHelper.DoLog(data, Request);
            //var userAgent = Request.Headers["User-Agent"].ToString() == "" ? Request.Headers["UserAgent"].ToString() : Request.Headers["User-Agent"].ToString();
            //int loginType = userAgent.ToUpper().Contains("CASAMIEL") ? 1 : 2;
            //if (userAgent.Contains("MicroMessenger"))
            //{
            //    loginType = 3;//微信端
            //}
            var loginInfo = this.LoginInfo;

            var handler = new JwtSecurityTokenHandler();
            JwtSecurityToken dtoken = handler.ReadJwtToken(token);
            var rsa = new RSAHelper(RSAType.RSA2, Encoding.UTF8, RSAHelper.privateKey, RSAHelper.publicKey);

            var exp = dtoken.Payload.Exp;
            string mobile = rsa.Decrypt(dtoken.Payload.Jti);
            if (exp < new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()) {
                var a = new { code = -14, msg = "登录凭证已过期，请重新登陆" };
                return new JsonResult(a);
            }

            var command = new CreateMemberAccessTokenComand(mobile, loginInfo.Item1, data.registration_Id) { RequestUrl = Request.GetShortUri(), UserIP = Request.GetUserIp() };
            var result = await _mediator.Send(command).ConfigureAwait(false);

            var member = await _memberService.FindAsync<ICasaMielSession>(mobile).ConfigureAwait(false);
            var memberdata = new { Mobile = member.Mobile, Nick = member.Nick, Birthday = member.Birthday, Sex = member.Sex, TrueName = member.TrueName, Email = member.Email };
			//return Ok(new { code = 0, data = result, member = memberdata });
			return Ok(new { code = 0, data = result, member = memberdata, content = new { data= result, member= memberdata }, msg = "" });

        }
        /// <summary>
        /// 手机验证码
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        /// <remarks>
        /// {"mobile":"xxxxxxxxx"}
        /// </remarks>
        [HttpPost]
        //[CustomRoute()]
        [Route("[action]")]
        public async Task<BaseResult<string>> GetSmsCode([FromBody] GetSmsCodeRequest data)
        {
            if (data == null) {
                throw new ArgumentNullException(nameof(data));
            }

            //if (string.IsNullOrEmpty(data["mobile"].ToString())) {
            //    return new BaseResult<string>("", -5, "手机号不能为空");
            //}
            string mobile = data.Mobile;
            if (string.IsNullOrEmpty(mobile)) {
                return new BaseResult<string>("", -5, "手机号不能为空");
            }

            var msg = await _mobileCheckCode.SendCheckCodeAsync(mobile).ConfigureAwait(false);
            if (string.IsNullOrEmpty(msg)) {
                return new BaseResult<string>("", 0, "验证码已发送");
            }
            return new BaseResult<string>("", -6, msg);
        }

        /// <summary>
        /// 注销
        /// </summary>
        /// <param name="token">用户token</param>
        /// <returns></returns>
        [HttpPost]
        [Route("[action]")]
        [TypeFilterAttribute(typeof(CheckTokenAttribute))]
        public async Task<BaseResult<string>> Logout([FromHeader(Name = "u-token")] string token)
        {
            var mobile = MemberHelper.GetMobile(token);
            var logoutcommand = new LogoutCommand(mobile, LoginInfo.Item1) { RequestUrl = Request.GetShortUri(), UserIP = Request.GetUserIp() };
            var result = await _mediator.Send(logoutcommand).ConfigureAwait(false);
            return new BaseResult<string>("", 0, "注销成功！");
        }
        /// <summary>
        /// 登陆
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("[action]")]
        public async Task<IActionResult> Login([FromBody]LoginReq data)
        {
            if (data == null) {
                throw new ArgumentNullException(nameof(data));
            }

            ConsoleHelper.DoLog(data, Request);
            var loginInfo = LoginInfo;
            var source = loginInfo.Item2;
            //var userAgent = Request.GetUserAgent();
            int loginType = loginInfo.Item1;
            
            var sucess = await _mobileCheckCode.CheckSmsCodeAsync(data.Mobile, data.Yzm, false).ConfigureAwait(false);
            var smscode = sucess["code"].ToInt16(-9);
            if (smscode != 0) {
                return new JsonResult(new { code = smscode, msg = sucess["msg"].ToString() });
            }

            var command = new LoginCommand { InvitationCode=data.InvitationCode, Mobile = data.Mobile, LoginType = loginType, Registration_Id = data.Registration_Id, RequestUrl = Request.GetShortUri(), UserIP = Request.GetUserIp(), Source = source };
            var result = await _mediator.Send(command).ConfigureAwait(false);
            var member = result.Item1;
            var memberdata = new { Mobile = member.Mobile, Nick = member.Nick, Birthday = member.Birthday, Sex = member.Sex, TrueName = member.TrueName, Email = member.Email, cardno = result.Item3 };
            //return new JsonResult(new { code = 0, data = result.Item2, member = memberdata });
            return Ok(new { code = 0, data = result.Item2, member = memberdata, content = new { data = result.Item2, member= memberdata }, msg = "" });
        }

        /// <summary>
        /// 注册会员申请虚拟卡
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("[action]")]
        public async Task<IActionResult> RegIcselfregist([FromBody] RegIcselfregistReq data)
        {
            if (data == null) {
                throw new ArgumentNullException(nameof(data));
            }

            ConsoleHelper.DoLog(data, Request);
            var loginInfo = base.LoginInfo;

            var sucess = await _mobileCheckCode.CheckSmsCodeAsync(data.Mobile, data.Yzm, false).ConfigureAwait(false);
            var smscode = Convert.ToInt16(sucess["code"].ToString(), CultureInfo.CurrentCulture);
            if (smscode != 0) {
                return new JsonResult(sucess);
            }

            var entity = await _memberService.FindAsync<ICasaMielSession>(data.Mobile).ConfigureAwait(false);
            if (entity != null) {
                return new JsonResult(new { code = -20, msg = "手机号已注册，请登录" });
            }
            //_cacheService.Remove(Constant.MYCARDS_PREFIX + data.Mobile);
            var newcard = await _iicApiService.Icselfregist(data.Mobile, $"{LoginInfo.Item3}099".ToInt32(0)).ConfigureAwait(false);
            if (newcard.code == 0) {
                var jobj = JsonConvert.DeserializeObject<JObject>(newcard.content);
                logger.Trace($"新用户[{data.Mobile}]注册会员卡，卡号[{ jobj["cardno"].ToString()}]");
                var logdata = new UserLog { Url = Request.GetShortUri(), OPInfo = $"新用户注册会员卡，卡号[{jobj["cardno"].ToString()}]", OPTime = DateTime.Now, UserName = data.Mobile, UserIP = Request.GetUserIp() };
                await _userLog.AddAsync<ICasaMielSession>(logdata).ConfigureAwait(false);

                if (entity == null) {
                    entity = new Member { InvitationCode=data.InvitationCode, Mobile = data.Mobile, CreateDate = DateTime.Now, LastLoginDate = DateTime.Now, Source = loginInfo.Item2 };
                    await _memberService.AddAsync<ICasaMielSession>(entity).ConfigureAwait(false);
                    await AddReferralAsync(data.Mobile, data.InvitationCode).ConfigureAwait(false);
                } else {
                    entity.LastLoginDate = DateTime.Now;
                    await _memberService.UpdateLastLoginDateAsync<ICasaMielSession>(entity.ID, DateTime.Now).ConfigureAwait(false);
                    //await _memberService.UpdateAsync<ICasaMielSession>(entity).ConfigureAwait(false);
                }
                var mcard = new MemberCard();
                mcard.M_ID = entity.ID;
                mcard.CardNO = jobj["cardno"].ToString();
                mcard.Mobile = data.Mobile;
                mcard.IsBind = true;
                mcard.CardType = "2";
                mcard.BindTime = DateTime.Now;
                mcard.CreateTime = DateTime.Now;
                mcard.Source = 15;
                await _memberCard.AddAsync<ICasaMielSession>(mcard).ConfigureAwait(false);
                var command = new CreateMemberAccessTokenComand(data.Mobile, loginInfo.Item1, data.Registration_Id) { RequestUrl = Request.GetShortUri(), UserIP = Request.GetUserIp() };
                var token = await _mediator.Send(command).ConfigureAwait(false);

                var memberdata = new { Mobile = entity.Mobile, Nick = entity.Nick, Birthday = entity.Birthday, Sex = entity.Sex, TrueName = entity.TrueName, Email = entity.Email, cardno = mcard.CardNO,entity.InvitationCode };
                return Ok(new { code = 0, data = token, member = memberdata });
            }

            return Ok(new { code = newcard.code, content = newcard.content, msg = newcard.msg });
        }


        /// <summary>
        /// 
        /// </summary>
        /// <param name="mobile"></param>
        /// <param name="InvitationCode"></param>
        /// <returns></returns>
        private async Task AddReferralAsync(string mobile,string InvitationCode)
        {
            if (_casamielSettings.ApiName == "doncoApi" && !string.IsNullOrEmpty(InvitationCode)) {
                try {
                    await _storeApiService.AddReferral(mobile,InvitationCode).ConfigureAwait(false);
                } catch (Exception ex) {
                    logger.Error($"AddReferral:{ex.StackTrace}");
                }

            }
        }
        /// <summary>
        /// 注册会员并绑卡
        /// </summary>
        /// <param name="data"></param>
        /// <returns></returns>
        [HttpPost]
        [Route("[action]")]
        public async Task<IActionResult> RegBindCard([FromBody] RegBindCardReq data)
        {
            if (data == null) {
                throw new ArgumentNullException(nameof(data));
            }

            ConsoleHelper.DoLog(data, Request);
            var source = 0;
            var userAgent = string.IsNullOrEmpty(Request.Headers["User-Agent"].ToString()) ? Request.Headers["UserAgent"].ToString() : Request.Headers["User-Agent"].ToString();
            int loginType = userAgent.Contains("CASAMIEL", StringComparison.CurrentCultureIgnoreCase) ? 1 : 2;
            if (loginType == 1) {
                source = 1;
            }
            if (userAgent.Contains("MicroMessenger", StringComparison.CurrentCultureIgnoreCase)) {
                loginType = 3;
                source = 2;
            }
            var sucess = await _mobileCheckCode.CheckSmsCodeAsync(data.Mobile, data.Yzm, false).ConfigureAwait(false);
            var smscode = Convert.ToInt16(sucess["code"].ToString(), CultureInfo.CurrentCulture);
            if (smscode != 0) {
                return new JsonResult(new { code = smscode, msg = sucess["msg"].ToString() });
            }
            var cardinfo = await _memberCard.FindAsync<ICasaMielSession>(data.Cardno).ConfigureAwait(false);
            if (cardinfo != null && cardinfo.Mobile != data.Mobile) {
                return new JsonResult(new { code = 22, msg = "卡号与注册手机号码不符" });
            }
            //_cacheService.Remove(Constant.MYCARDS_PREFIX + data.Mobile);
            var entity = await _memberService.FindAsync<ICasaMielSession>(data.Mobile).ConfigureAwait(false);
            var mcards = await _memberCard.GetListAsync<ICasaMielSession>(data.Mobile).ConfigureAwait(false);
            var content = "";
            var bandcard = await _iicApiService.Icregist(data.Cardno, data.Mobile, 15).ConfigureAwait(false);
            if (bandcard != null) {
                content = bandcard.content;
                if (bandcard.code == 0 || bandcard.code == 101 || bandcard.code == 8) {
                    if (entity == null) {
                        entity = new Member { InvitationCode=data.InvitationCode, Mobile = data.Mobile, CreateDate = DateTime.Now, LastLoginDate = DateTime.Now, Source = source };
                        await _memberService.AddAsync<ICasaMielSession>(entity).ConfigureAwait(false);
                        // await _memberRepository.UnitOfWork.SaveEntitiesAsync();
                        await AddReferralAsync(data.Mobile, data.InvitationCode).ConfigureAwait(false);
                        var mcard = new MemberCard();
                        mcard.CardNO = data.Cardno;
                        mcard.M_ID = entity.ID;
                        mcard.CardType = "1";
                        mcard.Mobile = data.Mobile;
                        mcard.IsBind = true;
                        mcard.BindTime = DateTime.Now;
                        mcard.CreateTime = DateTime.Now;
                        mcard.Source = 15;
                        await _memberCard.AddAsync<ICasaMielSession>(mcard).ConfigureAwait(false);
                        //await _memberCard.UnitOfWork.SaveEntitiesAsync();

                        var logdata = new UserLog { Url = Request.GetShortUri(), OPInfo = $"新用户注册绑卡，卡号[{data.Cardno}]", OPTime = DateTime.Now, UserName = data.Mobile, UserIP = Request.GetUserIp() };
                        await _userLog.AddAsync<ICasaMielSession>(logdata).ConfigureAwait(false);
                    } else {
                        var list = mcards.Where(a => a.IsBind == true && (a.CardType == "1" || a.CardType == "2")).ToList();
                        if (list.Any()) {
                            if (list.Count(c => c.CardNO == data.Cardno) == 1) {
                                goto resutl;
                            }
                            return new JsonResult(new { code = "-8", msg = "您已经绑过卡" });
                        }
                        var mc = mcards.FirstOrDefault(c => c.CardNO == data.Cardno);
                        if (mc == null) {
                            mc = new MemberCard {
                                M_ID = entity.ID,
                                CardNO = data.Cardno,
                                Mobile = data.Mobile,
                                IsBind = true,
                                CardType = "1",
                                BindTime = DateTime.Now,
                                CreateTime = DateTime.Now,
                                Source = 15
                            };
                            await _memberCard.AddAsync<ICasaMielSession>(mc).ConfigureAwait(false);
                            var logdata = new UserLog { Url = Request.GetShortUri(), OPInfo = $"新用户注册绑卡，卡号[{data.Cardno}]", OPTime = DateTime.Now, UserName = data.Mobile, UserIP = Request.GetUserIp() };
                            await _userLog.AddAsync<ICasaMielSession>(logdata).ConfigureAwait(false);
                        } else {
                            mc.IsBind = true;
                            mc.BindTime = DateTime.Now;
                            await _memberCard.UpdateAsync<ICasaMielSession>(mc).ConfigureAwait(false);
                        }
                    }
                } else {
                    return new JsonResult(new { code = bandcard.code, msg = bandcard.msg });
                }
            }

        resutl:
            if (entity != null) {
                entity.LastLoginDate = DateTime.Now;
                await _memberService.UpdateLastLoginDateAsync<ICasaMielSession>(entity.ID, DateTime.Now).ConfigureAwait(false);
                //await _memberService.UpdateAsync<ICasaMielSession>(entity).ConfigureAwait(false);
            }
            var command = new CreateMemberAccessTokenComand(data.Mobile, loginType, data.Registration_Id) { RequestUrl = Request.GetShortUri(), UserIP = Request.GetUserIp() };
            var token = await _mediator.Send(command).ConfigureAwait(false);
            var memberdata = new { Mobile = entity.Mobile, Nick = entity.Nick, Birthday = entity.Birthday, Sex = entity.Sex, TrueName = entity.TrueName, Email = entity.Email, cardno = data.Cardno,entity.InvitationCode };
            return Ok(new { code = 0, data = token, member = memberdata, content = content });
        }

    }
}